package com.ee.chat.api.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ee.chat.api.common.CommonService;
import com.ee.chat.api.service.IIMService;
import com.ee.chat.api.task.CallTask;
import com.ee.chat.common.bean.Result;
import com.ee.chat.common.dao.*;
import com.ee.chat.common.entity.*;
import com.ee.chat.common.serconfig.MyNeteaseApp;
import com.ee.chat.common.service.IGeneralService;
import com.ee.chat.common.service.IUserImAnalysisService;
import com.ee.chat.common.service.IYieldService;
import com.ee.chat.common.util.ConstantsUtil;
import com.ndhutu.ee.util.DateUtil;
import com.ndhutu.ee.util.SensitiveWordUtil;
import com.ndhutu.ee.util.StringUtil;
import com.ndhutu.ee.util.netease.call.Call2Util;
import com.ndhutu.ee.util.netease.im.IMUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.time.ZoneOffset;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @Author Shane
 * @Date 2019/10/5 23:20
 */
@Service
public class IMServiceImpl implements IIMService {
    private Logger log = LoggerFactory.getLogger(IMServiceImpl.class);

    @Resource
    GiftConfigMapper giftConfigMapper;
    @Resource
    UserWalletMapper userWalletMapper;
    @Resource
    UserImLogMapper userImLogMapper;
    @Resource
    UserConsumeLogMapper userConsumeLogMapper;
    @Resource
    HostMapper hostMapper;
    @Resource
    UserCallLogMapper userCallLogMapper;
    @Resource
    HostLevelConfigMapper hostLevelConfigMapper;
    @Resource
    UserToHostLableLibMapper userToHostLableLibMapper;
    @Resource
    UserToHostLogMapper userToHostLogMapper;
    @Resource
    UserToHostLogLableMapper userToHostLogLableMapper;
    @Resource
    UserBlacklistMapper userBlacklistMapper;
    @Resource
    UserComplaintLogMapper userComplaintLogMapper;
    @Resource
    UserMapper userMapper;
    @Resource
    UserLableLibMapper userLableLibMapper;
    @Resource
    SysConfigMapper sysConfigMapper;
    @Resource
    HostCallContentMapper hostCallContentMapper;
    @Resource
    UserSetMapper userSetMapper;
    @Resource
    SysSensitiveWordLibMapper sysSensitiveWordLibMapper;
    @Resource
    SysKeyWordLibMapper sysKeyWordLibMapper;
    @Resource
    UserVipMapper userVipMapper;
    @Resource
    UserConsumeConfigMapper userConsumeConfigMapper;
    @Resource
    UserGiftBuyLogMapper userGiftBuyLogMapper;

    @Resource
    IGeneralService generalService;
    @Resource
    CommonService commonService;
    @Resource
    IYieldService yieldService;
    @Resource
    CallTask callTask;
    @Resource(name = "stringRedisTemplate")
    StringRedisTemplate redisTemplate;
    @Resource
    MyNeteaseApp app;
    @Resource
    IUserImAnalysisService userImAnalysisService;

    //敏感词DFA集合
    private Map<String, Object> sensitiveWordMap;
    //关键词DFA集合
    private Map<String, Object> keyWordMap;

    public Map<String, Object> getSensitiveWordMap() {
        return sensitiveWordMap;
    }

    public void setSensitiveWordMap(Map<String, Object> sensitiveWordMap) {
        this.sensitiveWordMap = sensitiveWordMap;
    }

    public Map<String, Object> getKeyWordMap() {
        return keyWordMap;
    }

    public void setKeyWordMap(Map<String, Object> keyWordMap) {
        this.keyWordMap = keyWordMap;
    }

    @PostConstruct
    public void init(){
        //敏感词
        Object sensitiveWordObj = redisTemplate.opsForHash().get("data", "sensitiveWord");
        if(sensitiveWordObj == null){
            List<String> words = sysSensitiveWordLibMapper.getWords();
            sensitiveWordMap = SensitiveWordUtil.init(new HashSet<>(words));

            //添加缓存
            redisTemplate.opsForHash().put("data", "sensitiveWord", JSONObject.toJSONString(sensitiveWordMap));
        }else{
            sensitiveWordMap = JSONObject.parseObject(sensitiveWordObj+"", Map.class);
        }

        //关键词
        Object keyWordObj = redisTemplate.opsForHash().get("data", "keyWord");
        if(keyWordObj == null){
            List<String> words = sysKeyWordLibMapper.getWords();
            keyWordMap = SensitiveWordUtil.init(new HashSet<>(words));

            //添加缓存
            redisTemplate.opsForHash().put("data", "keyWord", JSONObject.toJSONString(keyWordMap));
        }else{
            keyWordMap = JSONObject.parseObject(keyWordObj+"", Map.class);
        }
    }

    @Override
    public Result getGifts(String token) throws Exception {
        Map<String, Object> data = new HashMap<>();

        Integer userId = commonService.getUserId(token);

        List<Map<String, Object>> gifts = giftConfigMapper.getGifts();
        data.put("gifts", gifts);

        if(userId == null){
            data.put("coin", 0);
        }else{
            UserWallet userWallet = userWalletMapper.getByUserId(userId);
            data.put("coin", userWallet == null ? 0 : userWallet.getActiveCoin());
        }

        return Result.returnSuccess(data);
    }

    @Override
    public Result beforeStartCall(String token, Integer toUserId) throws Exception {
        Map<String, Object> data = new HashMap<>();
        Integer fromUserId = commonService.getUserId(token);

        //客服id
        Integer customerAccount = Integer.parseInt(sysConfigMapper.getValue("customer_account"));

        Host fromHost = hostMapper.selectByUserId(fromUserId);
        Host toHost = hostMapper.selectByUserId(toUserId);

        if((fromHost == null && toHost == null) || (fromHost != null && toHost != null)){
            return Result.returnResult(20005, "相同用户间不能进行通讯");
        }

        //客服禁止视频通话
        if(customerAccount.equals(fromUserId) || customerAccount.equals(toUserId)){
            return Result.returnResult(20006, "官方客服无法视频通话");
        }

        //禁用判断
        UserSet fromUserSet = userSetMapper.selectByUserId(fromUserId);
        if(fromUserSet != null && fromUserSet.getCall() == 1){
            return Result.returnResult(20007, "您已被禁止视频通话，详情请咨询客服");
        }
        UserSet toUserSet = userSetMapper.selectByUserId(toUserId);
        if(toUserSet != null && toUserSet.getIm() == 1){
            return Result.returnResult(20008, "对方已被禁用视频通话，请稍后再试");
        }

        //拉黑判断
        UserBlacklist userBlacklist = userBlacklistMapper.select(toUserId, fromUserId);
        if(userBlacklist != null){
            return Result.returnResult(20003, "您已被对方拉黑，无法主动进行联系");
        }

        //勿扰判断
        if(toUserSet != null && toUserSet.getDnd() == 1){
            return Result.returnResult(20009, "对方已开启勿扰模式，无法主动联系");
        }

        //余额判断
        UserWallet userWallet = null;
        Host host = null;
        if(fromHost == null){
            userWallet = userWalletMapper.getByUserId(fromUserId);
            host = toHost;
        }else{
            userWallet = userWalletMapper.getByUserId(toUserId);
            host = fromHost;
        }
        HostLevelConfig hostLevelConfig = hostLevelConfigMapper.selectById(host.getChargeId());
        if(userWallet == null || userWallet.getActiveCoin() < hostLevelConfig.getCharge()){
            return Result.returnResult(20004, "金币不足，请先进行充值");
        }

        String callId = StringUtil.getUUIDStr();
        UserCallLog userCallLog = new UserCallLog( callId, fromUserId, toUserId, fromHost == null ? 1 : 0, hostLevelConfig.getCharge(), hostLevelConfig.getEarn());
        userCallLogMapper.insert(userCallLog);

        //记录通话信息，该值记录每天当天的数据
        String key = ConstantsUtil.USER_CALL + "from:" + fromUserId;
        Map<Object, Object> call = redisTemplate.opsForHash().entries(key);
        if(call == null){
            call = new HashMap<>();
            call.put("success", "0");
            call.put("today_success", "0");
        }
        String temp = "total";
        call.put(temp, call.get(temp) == null ? "1" : Integer.parseInt(call.get(temp)+"") + 1 +"");
        temp = "today";
        boolean today = DateUtil.getCurrTimeStr(DateUtil.pattern_day).equals(call.get(temp));
        if(!today){
            call.put(temp, DateUtil.getCurrTimeStr(DateUtil.pattern_day));
        }
        temp = "today_total";
        call.put(temp, call.get(temp) == null ? "1" : Integer.parseInt(call.get(temp)+"") + 1 +"");
        redisTemplate.opsForHash().putAll(key, call);

        //获取通话token
        Long uid = Long.parseLong(fromUserId + "");
        String nertcToken = Call2Util.getToken(uid, app);

        data.put("callId", callId);
        data.put("nertcToken", nertcToken);
        return Result.returnSuccess(data);
    }

    /**
     * 开始通话
     * @Author Shane
     * @Date 2019/10/2916:27
     * @param
     * @return
     **/
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result startCall(String token, Integer toUserId, String channelId, String callId) throws Exception {
        Integer userId = commonService.getUserId(token);

        String key = ConstantsUtil.USER_FLAG + "startCall:" + channelId;
        Boolean lock;
        do{
            lock = redisTemplate.opsForValue().setIfAbsent(key, "1", 10, TimeUnit.SECONDS);
            if(lock == false){
                Thread.sleep(200);
            }
        }while (!lock);

        UserCallLog userCallLog = userCallLogMapper.selectByChannelId(channelId);
        if(userCallLog != null){
            //删除状态锁
            redisTemplate.delete(key);
            return Result.returnSuccess(null);
        }

        //记录通话信息
        String callKey = ConstantsUtil.USER_CALL + "from:" + userId;
        Integer success = Integer.parseInt(redisTemplate.opsForHash().get(callKey, "success")+"");
        Integer today_success = Integer.parseInt(redisTemplate.opsForHash().get(callKey, "today_success")+"");
        redisTemplate.opsForHash().put(callKey, "success", success + 1);
        redisTemplate.opsForHash().put(callKey, "today_success", today_success + 1);

        //计算succ、consume
        String imKey = ConstantsUtil.USER_IM + "send:" + userCallLog.getFromUserId() + ":" + userCallLog.getToUserId();
        countSucc(imKey);

        Date date = new Date();
        Host host = hostMapper.selectByUserId(userId);
        UserWallet userWallet;
        if(host == null){
            userWallet = userWalletMapper.getByUserId(userId);
            if(userWallet == null){
                userWallet = new UserWallet(userId, 0, 0, 0.0, 0.0);
            }
        }else{
            userWallet = userWalletMapper.getByUserId(toUserId);
            if(userWallet == null){
                userWallet = new UserWallet(toUserId, 0, 0, 0.0, 0.0);
            }
        }

        Integer coin = userCallLog.getCharge();
        if(userWallet.getActiveCoin() < coin){
            return Result.returnResult(3, "金币不足，请先进行充值");
        }

        //添加定时任务
        callTask.addCallTask(channelId, date);

        //更新通话记录
        userCallLog.setChannelId(channelId);
        userCallLog.setBeginTime(date);
        userCallLog.setTotalCoin(coin);
        /*
         * 通话10秒后主播才获取收益
         */
//        userCallLog.setTotalCredit(userCallLog.getEarn());
        userCallLogMapper.updateById(userCallLog);

        //添加消费信息
//        walletService.consume(userHoldBuyLog.getUserId(), 0, userHoldBuyLog.getHostUserId(), userHoldBuyLog.getId()+"", coin, credit);

        /*
         * 通话10秒后主播才获取收益
         */
        //添加消费记录
        UserConsumeLog userConsumeLog = new UserConsumeLog(userCallLog.getHost() == 0 ? userCallLog.getFromUserId() : userCallLog.getToUserId(), 0, userCallLog.getHost() == 1 ? userCallLog.getFromUserId() : userCallLog.getToUserId(), userCallLog.getId()+"", coin, 0.0);
        userConsumeLogMapper.insert(userConsumeLog);
        //更新用户钱包
        yieldService.updateUserWallet(userCallLog.getHost() == 0 ? userCallLog.getFromUserId() : userCallLog.getToUserId(), userConsumeLog.getId(), 1, -coin.doubleValue(), "视频通话", 0);


        //更新用户状态
        User user = new User();
        user.setId(userCallLog.getFromUserId());
        user.setOnline(2);  //在聊
        userMapper.updateById(user);
        User hostUser = new User();
        hostUser.setId(userCallLog.getToUserId());
        hostUser.setOnline(2);  //在聊
        userMapper.updateById(hostUser);

        //删除状态锁
        redisTemplate.delete(key);

        return Result.returnSuccess(null);
    }

    /**
     * 结束通话
     * @Author Shane
     * @Date 2019/10/2916:27
     * @param
     * @return
     **/
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result endCall(String token, String channelId) throws Exception {
        Integer userId = commonService.getUserId(token);

        //拦截同时结束通话
        String key = ConstantsUtil.USER_FLAG + "endCall:" + channelId;
        Boolean lock;
        do{
            lock = redisTemplate.opsForValue().setIfAbsent(key, "1", 10, TimeUnit.SECONDS);
            if(lock == false){
                Thread.sleep(200);
            }
        }while (!lock);

        callTask.endCall(channelId, new Date());

        //删除状态锁
        redisTemplate.delete(key);

        return Result.returnSuccess(null);
    }

    /**
     * 获取通话评价信息
     * @Author Shane
     * @Date 2019/11/1 15:58
     * @param
     * @return
     */
    @Override
    public Result getCallEvaluateInfo(String token, String channelId) throws Exception {
        Map<String, Object> data = new HashMap<>();

        Map<String, Object> host = userCallLogMapper.getHoldHostInfo(channelId);
        List<UserToHostLableLib> goodLables = userToHostLableLibMapper.selectByType(0);
        List<UserToHostLableLib> badLables = userToHostLableLibMapper.selectByType(1);

        data.put("host", host);
        data.put("goodLables", goodLables);
        data.put("badLables", badLables);

        return Result.returnSuccess(data);
    }

    /**
     * 通话评价
     * @Author Shane
     * @Date 2019/11/6 15:20
     * @param
     * @return
     **/
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result callEvaluate(String token, String channelId, Integer type, String lableIds) throws Exception {
        UserCallLog userCallLog = userCallLogMapper.selectByChannelId(channelId);

        UserToHostLog userToHostLog = null;
        if(userCallLog.getHost() == 0){
            userToHostLog = new UserToHostLog(userCallLog.getFromUserId(), userCallLog.getToUserId(), userCallLog.getId(), type);
        }else{
            userToHostLog = new UserToHostLog(userCallLog.getToUserId(), userCallLog.getFromUserId(), userCallLog.getId(), type);
        }
        userToHostLogMapper.insert(userToHostLog);

        for(String lableId : lableIds.split(",")){
            UserToHostLogLable userToHostLogLable = new UserToHostLogLable(userToHostLog.getId(), Integer.parseInt(lableId));
            userToHostLogLableMapper.insert(userToHostLogLable);
        }

        //更新好评率
        Integer goodRate = 100;
        int goodNum = userToHostLogMapper.getUserEvaluateNum(userToHostLog.getHostUserId(), 0);
        int totalNum = userToHostLogMapper.getUserEvaluateNum(userToHostLog.getHostUserId(), null);
        goodRate = goodNum * 100/totalNum;

        Host host = hostMapper.selectByUserId(userToHostLog.getHostUserId());
        if(!host.getGoodRate().equals(goodRate)){
            host.setGoodRate(goodRate);
            hostMapper.updateById(host);
        }

        //通知主播用户评价
        List<Integer> ids = new ArrayList<>();
        for(String lableId : lableIds.split(",")){
            ids.add(Integer.parseInt(lableId));
        }
        List<Map<String, Object>> lables = userLableLibMapper.getUserLable(ids);
        String msg = "通话评价：";
        for(Map<String, Object> lable : lables){
            msg += lable.get("name") + "";
        }
        Map<String, Object> body = new HashMap<>();
        body.put("msg", msg);
        IMUtil.sendMsg(app.getIdPrefix() + userToHostLog.getUserId(), app.getIdPrefix() + userToHostLog.getHostUserId(), 10, body, app);

        return Result.returnSuccess(null);
    }

    /**
     * 获取拉黑状态
     * @Author Shane
     * @Date 2019/11/6 15:22
     * @param
     * @return
     **/
    @Override
    public Result getBlock(String token, Integer toUserId) throws Exception {
        Integer userId = commonService.getUserId(token);
        Map<String, Object> data = new HashMap<>();

        UserBlacklist blacklist = userBlacklistMapper.select(userId, toUserId);

        if(blacklist == null){
            data.put("block", 0);
        }else{
            data.put("block", 1);
        }

        return Result.returnSuccess(data);
    }


    @Override
    public Result block(String token, Integer toUserId, Integer block) throws Exception {
        Integer userId = commonService.getUserId(token);

        UserBlacklist userBlacklist = userBlacklistMapper.select(userId, toUserId);
        if(block == 0){ //取消拉黑
            if(userBlacklist == null){
                return Result.returnFailure("尚未拉黑该用户，不存在取消拉黑");
            }

            //取消拉黑
//            IMUtil.setSpecialRelation(userId, toUserId, block, 1, app);

            userBlacklistMapper.deleteById(userBlacklist.getId());
        }else if(block == 1){   //拉黑
            if(userBlacklist != null){
                return Result.returnFailure("已经拉黑该用户，无需重复拉黑");
            }

            //拉黑
//            IMUtil.setSpecialRelation(userId, toUserId, block, 1 , app);

            userBlacklist = new UserBlacklist(userId, toUserId);
            userBlacklistMapper.insert(userBlacklist);
        }

        return Result.returnSuccess(null);
    }

    @Override
    public Result complaint(String token, Integer toUserId, String content, String images) throws Exception {
        Integer userId = commonService.getUserId(token);

        UserComplaintLog userComplaintLog = new UserComplaintLog(userId, toUserId, content, images);
        userComplaintLogMapper.insert(userComplaintLog);

        return Result.returnSuccess(null);
    }

    @Override
    public Object getMoreMsgRemind(String token) throws Exception {
        Map<String, Object> data = new HashMap<>();
        Integer userId = commonService.getUserId(token);

        //获取系统已经发送的数据数量
        Date date = new Date();
        String day = DateUtil.format(date, DateUtil.pattern_day);
        Date beginTime = DateUtil.parse(day+" 00:00:00", DateUtil.pattern_general);
        Date endTime = DateUtil.parse(day+" 23:59:59", DateUtil.pattern_general);
        int num = userImLogMapper.getSysSendMsgNum(userId, "TEXT", beginTime, endTime);

        //获取弹窗标记
        String key = ConstantsUtil.USER_FLAG + "kindReminder:" + userId;
        Object m = redisTemplate.opsForHash().get(key, "mark");
        if(num >= 5 && m == null){
            data.put("kindReminder", 1);

            redisTemplate.opsForHash().put(key, "mark", "1");
        }else{
            data.put("kindReminder", 0);
        }

        return Result.returnSuccess(data);
    }

    @Override
    public Object imCallback(String message){
        Map<String, Object> data = new HashMap<>();
        data.put("errCode", 1); //不允许通过

        try {
            Map<String, Object> map = JSONObject.parseObject(message, Map.class);
            Integer eventType = Integer.parseInt(map.get("eventType")+"");
            Integer fromUserId = Integer.parseInt((map.get("fromAccount")+"").replace(app.getIdPrefix(), ""));
            User fromUser = userMapper.selectById(fromUserId);
            Host fromHost = hostMapper.selectByUserId(fromUserId);
            String msgType = map.get("msgType")+"";
            String body = map.get("body")+"";

            //客服id
            Integer customerAccount = Integer.parseInt(sysConfigMapper.getValue("customer_account"));

            if(eventType == 1){ //P2P消息回调
                Integer toUserId = Integer.parseInt((map.get("to")+"").replace(app.getIdPrefix(), ""));
                Host toHost = hostMapper.selectByUserId(toUserId);

                //客服消息免费
                if(fromUserId.equals(customerAccount) || toUserId.equals(customerAccount)){
                    data.put("errCode", 0);
                    return data;
                }

                if((fromHost == null && toHost == null) || (fromHost != null && toHost != null)){
                    data.put("responseCode", 20005);    //相同用户间不能进行通讯
                    return data;
                }

                //禁用判断
                UserSet fromUserSet = userSetMapper.selectByUserId(fromUserId);
                if(fromUserSet != null && fromUserSet.getIm() == 1){
                    data.put("responseCode", 20001);    //您已被禁止发送消息，详情请咨询客服
                    return data;
                }
                UserSet toUserSet = userSetMapper.selectByUserId(toUserId);
                if(toUserSet != null && toUserSet.getIm() == 1){
                    data.put("responseCode", 20002);    //对方已被禁用消息，请稍后再试
                    return data;
                }

                //检查用户是否达到发送频率
                if(fromHost != null){
                    String key1 = ConstantsUtil.USER_IM + "send:" + toUserId + ":" + fromUserId;
                    Object consume = redisTemplate.opsForHash().get(key1, "consume");
                    if(consume == null || !"1".equals(Integer.parseInt(consume + ""))){
                        key1 = ConstantsUtil.USER_IM + "send:" + fromUserId + ":" + toUserId;
                        Object succ = redisTemplate.opsForHash().get(key1, "succ");
                        if(succ != null && Integer.parseInt(succ + "") >= 3){
                            data.put("responseCode", 20014);    //您已数次联系该用户未得到回复，暂无法主动联系
                            return data;
                        }
                    }
                }

                UserBlacklist userBlacklist = userBlacklistMapper.select(toUserId, fromUserId);
                if(userBlacklist != null){
                    data.put("responseCode", 20003);    //您已被对方拉黑，无法主动进行联系
                    return data;
                }

                //获取用户id
                int userId, hostUserId;
                if(fromHost == null){
                    userId = fromUserId;
                    hostUserId = toUserId;
                }else{
                    userId = toUserId;
                    hostUserId = fromUserId;
                }

                Date now = new Date();

                /***********************************************  消息合法校验 ******************************************/
                if("TEXT".equals(msgType)){
                    String bodyTemp = body.replaceAll("\\s*", "").replace("-", "").replace("—", "");

                    //hi消息免费
                    if("HI".equals(body.toUpperCase())){
                        data.put("errCode", 0);
                        return data;
                    }

                    //用户批量打招呼免费
                    if(fromUser != null){
                        int n = hostCallContentMapper.getUserCallContent(body);
                        if(n >= 1){
                            data.put("errCode", 0);
                            return data;
                        }
                    }

                    //检查敏感词
                    boolean flag = SensitiveWordUtil.contains(bodyTemp, sensitiveWordMap);
                    if(flag){
                        data.put("responseCode", 20010);    //消息中包含敏感词，不能发送
                        return data;
                    }

                    //匹配消息中是否包含手机号、微信号、qq号等
                    //匹配规则，连续四位以上的数字字符
                    String reger = "^.*[0-9a-zA-z]{4,}.*$";
                    if(StringUtil.matcher(bodyTemp, reger)){
                        data.put("responseCode", 20011);    //消息中包含联系信息，不能发送
                        return data;
                    }
                }

                if("TEXT".equals(msgType) || "AUDIO".equals(msgType)){
                    //用户消费过，主播才能发送自定义消息
                    if(fromHost != null){
                        int count = userConsumeLogMapper.getConsumeLogCount(userId, hostUserId);
                        if(count <= 0){
                            count = userImLogMapper.selectNotCallMessageCount(toUserId, fromUserId);
                            if(count <= 0){
                                boolean f = true;
                                if("TEXT".equals(msgType)){
                                    HostCallContent hostCallContent = hostCallContentMapper.selectByUserIdAndContent(hostUserId, body);
                                    if(hostCallContent != null){
                                        f = false;
                                    }
                                }
                                if(f){
                                    data.put("responseCode", 20012);    //尚未主动联系，不能发送自定义信息
                                    return data;
                                }
                            }
                        }
                    }
                }


                if("TEXT".equals(msgType)){
                    //主播发送消息不扣费
                    if(fromHost != null){
                        data.put("errCode", 0);
                        return data;
                    }

                    //每天的前5条消息免费
                    String day = DateUtil.format(now, DateUtil.pattern_day);
                    int freeCount = userImLogMapper.getMsgNum(userId, 0, DateUtil.parse(day+" 00:00:00"), DateUtil.parse(day+" 23:59:59"));
                    if(freeCount < 5){
                        data.put("errCode", 0);
                        return data;
                    }
                }

                if("CUSTOM".equals(msgType)){
                    //礼物消息可以通过
                    if(Integer.parseInt(JSONObject.parseObject(map.get("attach")+"").get("type")+"") != 0){
                        data.put("responseCode", 20013);    //未知礼物，无法发送
                        return data;
                    }
                }

                if("AUDIO".equals(msgType)){
                    //主播发送消息不扣费
                    if(fromHost != null){
                        data.put("errCode", 0);
                        return data;
                    }
                }

                UserVip userVip = userVipMapper.getByUserId(userId);
                UserWallet userWallet = userWalletMapper.getByUserId(userId);
                if("TEXT".equals(msgType)){
                    if(userVip == null || userVip.getEndTime().toInstant(ZoneOffset.of("+8")).toEpochMilli()-System.currentTimeMillis() <= 0){
                        UserConsumeConfig consumeConfig = userConsumeConfigMapper.selectByKeyword("sendTextMsg");
                        if(userWallet == null || userWallet.getActiveCoin() < consumeConfig.getCoin()){
                            data.put("responseCode", 20004);    //金币不足，请先进行充值
                            return data;
                        }
                        yieldService.consume(userId, 2, hostUserId, null, consumeConfig.getCoin(), consumeConfig.getEarn());
                    }

                }else if("CUSTOM".equals(msgType)){ //图片消息
                    Map<String, Object> attach = JSONObject.parseObject(map.get("attach")+"");
                    Map<String, Object> da = (Map<String, Object>) attach.get("data");
                    Integer giftId = Integer.parseInt(da.get("giftId")+"");
                    String linkedId = da.get("linkedId")+"";
                    Integer giftType = Integer.parseInt(da.get("giftType")+"");

                    GiftConfig giftConfig = giftConfigMapper.selectById(giftId);
                    UserWallet fromUserWallet = userWalletMapper.getByUserId(fromUserId);
                    if(fromUserWallet == null || fromUserWallet.getActiveCoin() < giftConfig.getCoin()){
                        data.put("responseCode", 20004);    //金币不足，请先进行充值
                        return data;
                    }

                    if(giftType == 2){  //通话送礼
                        UserCallLog userCallLog = userCallLogMapper.selectByChannelId(linkedId);
                        linkedId = userCallLog.getId()+"";
                    }
                    Integer id = null;
                    if(!StringUtil.isEmpty(linkedId)){
                        id = Integer.parseInt(linkedId);
                    }

                    //添加送礼记录
                    UserGiftBuyLog userGiftBuyLog = null;
                    if(giftType == 0){  //聊天送礼
                        userGiftBuyLog = new UserGiftBuyLog(fromUserId, toUserId, 1, id, giftId, giftConfig.getCoin(), giftConfig.getEarn());
                        yieldService.consume(fromUserId, 3, toUserId, null, giftConfig.getCoin(), giftConfig.getEarn());
                    }else if(giftType == 1){    //动态送礼
                        userGiftBuyLog = new UserGiftBuyLog(fromUserId, toUserId, 2, id, giftId, giftConfig.getCoin(), giftConfig.getEarn());
                        yieldService.consume(fromUserId, 4, toUserId, null, giftConfig.getCoin(), giftConfig.getEarn());
                    }else if(giftType == 2){    //通话送礼
                        userGiftBuyLog = new UserGiftBuyLog(fromUserId, toUserId, 0, id, giftId, giftConfig.getCoin(), giftConfig.getEarn());
                        yieldService.consume(fromUserId, 5, toUserId, null, giftConfig.getCoin(), giftConfig.getEarn());
                    }else if(giftType == 3){    //主页送礼
                        userGiftBuyLog = new UserGiftBuyLog(fromUserId, toUserId, 3, id, giftId, giftConfig.getCoin(), giftConfig.getEarn());
                        yieldService.consume(fromUserId, 6, toUserId, null, giftConfig.getCoin(), giftConfig.getEarn());
                    }else{
                        data.put("responseCode", 20004);    //未知礼物，无法发送
                        return data;
                    }
                    userGiftBuyLogMapper.insert(userGiftBuyLog);

                    //添加动态
                    UserOperationLog userOperationLog = new UserOperationLog(fromUserId, fromHost == null ? 0 : 1, 4, toUserId, userGiftBuyLog.getId());
                    generalService.addUserOperationLog(userOperationLog, null);

                }else if("AUDIO".equals(msgType)){  //语音消息
                    if(userVip == null || userVip.getEndTime().toInstant(ZoneOffset.of("+8")).toEpochMilli()-System.currentTimeMillis() <= 0){
                        UserConsumeConfig consumeConfig = userConsumeConfigMapper.selectByKeyword("sendVoiceMsg");
                        if(userWallet == null || userWallet.getActiveCoin() < consumeConfig.getCoin()){
                            data.put("responseCode", 20004);    //金币不足，请先进行充值
                            return data;
                        }
                        yieldService.consume(userId, 7, hostUserId, null, consumeConfig.getCoin(), consumeConfig.getEarn());
                    }

                }else if("NRTC_NETCALL".equals(msgType)){
                    data.put("responseCode", 20000);    //未知礼物，无法发送
                    return data;
                }

            }else if(eventType == 20){  //视频通话回调
                List<String> toAccountList = JSONObject.parseArray(map.get("toAccountList")+"", String.class);
                Integer toUserId = Integer.parseInt(toAccountList.get(0).replace(app.getIdPrefix(), ""));

                User toUser = userMapper.selectById(toUserId);
                Host toHost = hostMapper.selectByUserId(toUserId);

                //客服禁止音视频通话
                if(fromUserId.equals(customerAccount) || toUserId.equals(customerAccount)){
                    data.put("responseCode", 20006);    //官方客服无法视频通话
                    return data;
                }

                if((fromHost == null && toHost == null) || (fromHost != null && toHost != null)){
                    data.put("responseCode", 20005);    //相同用户间不能进行通讯
                    return data;
                }

                //禁用判断
                UserSet fromUserSet = userSetMapper.selectByUserId(fromUserId);
                if(fromUserSet != null && fromUserSet.getCall() == 1){
                    data.put("responseCode", 20007);    //您已被禁止视频通话，详情请咨询客服
                    return data;
                }
                UserSet toUserSet = userSetMapper.selectByUserId(toUserId);
                if(toUserSet != null && toUserSet.getIm() == 1){
                    data.put("responseCode", 20008);    //对方已被禁用视频通话，请稍后再试
                    return data;
                }

                UserBlacklist userBlacklist = userBlacklistMapper.select(toUserId, fromUserId);
                if(userBlacklist != null){
                    data.put("responseCode", 20003);    //您已被对方拉黑，无法主动进行联系
                    return data;
                }

                //勿扰判断
                if(toUserSet != null && toUserSet.getDnd() == 1){
                    data.put("responseCode", 20009);    //对方已开启勿扰模式，无法主动联系
                    return data;
                }

                //获取用户id
                int userId, hostUserId;
                if(fromHost == null){
                    userId = fromUserId;
                    hostUserId = toUserId;
                }else{
                    userId = toUserId;
                    hostUserId = fromUserId;
                }

                HostLevelConfig hostLevelConfig = hostLevelConfigMapper.selectById(hostMapper.selectByUserId(hostUserId).getChargeId());
                UserWallet userWallet = userWalletMapper.getByUserId(userId);
                if(fromHost == null && (userWallet == null || userWallet.getActiveCoin() < hostLevelConfig.getCharge())){
                    data.put("responseCode", 20004);    //金币不足，请先进行充值
                    return data;
                }
            }

            //允许通过
            data.put("errCode", 0);
            return data;

        }catch (Exception e){
            log.error("【IM回调处理失败】", e);
        }
        return data;
    }

    @Override
    public Object imCopyCallback(String message) throws Exception {
        Map<String, Object> map = JSONObject.parseObject(message, Map.class);
        Integer eventType = Integer.parseInt(map.get("eventType")+"");

        if(eventType == 1) { //会话类型消息抄送
            if("PERSON".equals(map.get("convType"))) {  //点对点
                Integer fromUserId = Integer.parseInt((map.get("fromAccount")+"").replace(app.getIdPrefix(), ""));
                Integer toUserId = Integer.parseInt((map.get("to")+"").replace(app.getIdPrefix(), ""));
                String type = map.get("msgType")+"";
                String msgid = map.get("msgidServer")+"";

                String key = ConstantsUtil.USER_IM + "msgid:" + msgid;
                Object isSys = redisTemplate.opsForHash().get(key, "is_sys");

                //消息
                String msg = null;
                Object bodyObj = map.get("body");
                if("AUDIO".equals(type) && bodyObj == null){
                    msg = "发来了一段语音";
                }else{
                    msg = map.get("body")+"";
                }

                //附加信息
                String attach = map.get("attach") == null ? null : map.get("attach")+"";
                //添加消息记录
                UserImLog userImLog = new UserImLog(msgid, map.get("msgTimestamp")+"", fromUserId, toUserId, type, msg, attach);

                if(isSys != null){
                    userImLog.setIsSys(Integer.parseInt(isSys+""));
                    redisTemplate.expire(key, -1, TimeUnit.MINUTES);

                }else{
                    Host fromHost = hostMapper.selectByUserId(fromUserId);
                    if(fromHost == null){   //用户发送
                        //用户批量打招呼
                        int num = hostCallContentMapper.getUserCallContent(msg);
                        if(num > 0 || "HI".equals(msg.toUpperCase())){
                            userImLog.setIsSys(3);
                        }

                    }else{  //主播发送
                        HostCallContent hostCallContent = hostCallContentMapper.selectByUserIdAndContent(fromUserId, msg);
                        if(hostCallContent != null  || "HI".equals(msg.toUpperCase())){
                            userImLog.setIsSys(4);
                        }
                    }

                    //判断是否包含关键词
                    if(userImLog.getIsSys() == null && "TEXT".equals(type)){
                        Set<String> keywords = SensitiveWordUtil.getSensitiveWord(msg, keyWordMap);
                        if(keywords != null && keywords.size() > 0){
                            StringBuffer buffer = new StringBuffer();
                            for(String keyword : keywords){
                                buffer.append(keyword+",");
                            }
                            userImLog.setKeywords(buffer.substring(0, buffer.length()-1));
                        }
                    }
                }
                userImLogMapper.insert(userImLog);

                //记录当天各类型消息数量
                isSys = userImLog.getIsSys() == null ? 0 : userImLog.getIsSys();
                String customerAccount = sysConfigMapper.getValue("customer_account");
                if(!customerAccount.equals(fromUserId) && !customerAccount.equals(toUserId)){
                    String key1 = ConstantsUtil.USER_IM + "from:" + fromUserId;
                    statImData(key1, type, isSys);  //统计用户im数据
                    String key2 = ConstantsUtil.USER_IM + "to:" + toUserId;
                    statImData(key2, type, isSys);
                    String key3 = ConstantsUtil.USER_IM + "send:" + fromUserId + ":" + toUserId;
                    statImData(key3, type, isSys);
                }

                //添加/更新消息分析记录
                if(userImLog.getIsSys() == null || userImLog.getIsSys() == 0){
                    userImAnalysisService.updateImAnalysis(fromUserId, type);
                }
            }

        }else if(eventType == 6 || eventType == 22) { //音视频/白板文件下载信息抄送
            List<Map> fileinfo = JSONArray.parseArray(map.get("fileinfo")+"", Map.class);
            if(fileinfo != null && fileinfo.size() > 0){
                for(Map<String, Object> info : fileinfo){
                    String channelId = info.get("channelid")+"";
                    String url = info.get("url")+"";
                    String vid = info.get("vid")+"";

                    UserCallLog userCallLog = userCallLogMapper.selectByChannelId(channelId);
                    if(userCallLog.getFile() == null){
                        userCallLog.setFile(url);
                    }else{
                        userCallLog.setFile(userCallLog.getFile()+","+url);
                    }
                    userCallLog.setVid(vid);
                    userCallLogMapper.updateById(userCallLog);
                }
            }

        }else if(eventType == 26){  //音视频房间结束抄送，收费1000/月

        }else if(eventType == 28){  //音视频房间开始抄送

        }
        return Result.returnSuccess(null);
    }

    /**
     * 统计im数据
     * @param key   缓存key
     * @param type  消息类型
     * @param isSys 系统消息状态
     * @throws Exception
     */
    private void statImData(String key, String type, Object isSys) throws Exception{
        String temp;
        Map imMap = redisTemplate.opsForHash().entries(key);
        if(imMap == null){
            imMap = new HashMap();
        }
        temp = "total";
        imMap.put(temp, imMap.get(temp) == null ? "1" : Integer.parseInt(imMap.get(temp)+"") + 1 + "");
        temp = type + "_total";
        imMap.put(temp, imMap.get(temp) == null ? "1" : Integer.parseInt(imMap.get(temp)+"") + 1 + "");
        if(isSys != null){
            temp = type + "_" + isSys + "_total";
            imMap.put(temp, imMap.get(temp) == null ? "1" : Integer.parseInt(imMap.get(temp)+"") + 1 + "");
        }
        temp = "today";
        boolean today = DateUtil.getCurrTimeStr(DateUtil.pattern_day).equals(imMap.get(temp));
        if(!today){
            imMap.put(temp, DateUtil.getCurrTimeStr(DateUtil.pattern_day));
        }
        temp = "today_total";
        imMap.put(temp, today ? imMap.get(temp) == null ? "1" : Integer.parseInt(imMap.get(temp)+"") + 1 + "" : "1");
        temp = "today_" + type + "_total";
        imMap.put(temp, today ? imMap.get(temp) == null ? "1" : Integer.parseInt(imMap.get(temp)+"") + 1 + "" : "1");
        temp = "today_" + type + "_" + isSys + "_total";
        imMap.put(temp, today ? imMap.get(temp) == null ? "1" : Integer.parseInt(imMap.get(temp)+"") + 1 + "" : "1");

        //计算succ、consume
        if(key.indexOf("send") > -1){
            countSucc(key);
        }

        redisTemplate.opsForHash().putAll(key, imMap);
    }

    /**
     * 处理succ、consume
     * @param key
     */
    private void countSucc(String key){
        Object succ = redisTemplate.opsForHash().get(key, "succ");
        redisTemplate.opsForHash().put(key, "succ", succ == null ? "1" : Integer.parseInt(succ+"") + 1 + "");
        redisTemplate.opsForHash().put(key, "consume", "1");

        String userIds = key.split("send:")[1];
        String fromUserId = userIds.split(":")[0], toUserId = userIds.split(":")[1];
        String key1 = ConstantsUtil.USER_IM + "send:" + toUserId + ":" + fromUserId;
        redisTemplate.opsForHash().put(key1, "succ", "0");
    }

    @Override
    public Result getCallToken(String token, Long uid) throws Exception {
        Map<String, Object> data = new HashMap<>();
        int userId = commonService.getUserId(token);

        String callToken = Call2Util.getToken(uid, app);
        data.put("nertcToken", callToken);

        return Result.returnSuccess(data);
    }

    public static void main(String[] args) {
        String json = "{\"fromNick\":\"人不聪明脑子笨ⅰ\",\"msgType\":\"TEXT\",\"msgidServer\":\"674945565901\",\"ip\":\"119.123.33.15\",\"fromAccount\":\"pp57738735\",\"fromClientType\":\"AOS\",\"fromDeviceId\":\"fad511bb-08ce-46b2-a328-55fa59d1a4f4\",\"eventType\":\"1\",\"body\":\"华府大道\",\"convType\":\"PERSON\",\"msgidClient\":\"b6ec759596164825a184200f40677cac\",\"resendFlag\":\"0\",\"msgTimestamp\":\"1616235083905\",\"port\":\"28672\",\"to\":\"pp10000003\"}";
        Map map = JSONObject.parseObject(json, Map.class);

        String fromAccount = map.get("fromAccount")+"";
        System.out.println("pp".equals(fromAccount.substring(0, 2)));
    }
}
